/*

This file is part of roomyak.

Copyright (C) 2008 Pixecur Technologies Incorporated (Esotera).
Visit Esotera at http://www.esoteras3.com
 
roomyak is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
 
roomyak is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
General Public License for more details.
 
You should have received a copy of the GNU General Public License
along with roomyak; see the file COPYING.  If not, write to 
Pixecur Technologies, 213-31 Peet Street, St. John's, NL, A1B 3W8. 
 
Linking this library statically or dynamically with other modules is
making a combined work based on this library.  Thus, the terms and
conditions of the GNU General Public License cover the whole
combination.
 
*/
package com.datasentinel.util.logging;


/*

 Originally obtained from:

 http://mytechrantings.blogspot.com/2007/04/pattern-formatter-for-javautillogging.html
 http://docs.google.com/Doc?id=dchx3v9x_6g2q5xb


* Copyright [2007] [Rohit B. Rai]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.

 
 */

import java.text.DateFormat;
import java.text.MessageFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.logging.Formatter;
import java.util.logging.LogManager;
import java.util.logging.LogRecord;

public class PatternFormatter extends Formatter
{


	/**
	
	Logger Name %LN
	Level %LV
	Time %TM
	Message %MG
	Source Class Name %SC
	Short Class Name %CN
	Source Method Name %SM
	Exception Class Short Name %EN
	Exception Message %EX
	Exception Stack Trace %ST


	*
	* The default log format is "[%LN - %LV] %TM: %MG"
	* 
	* And exception format is [%LN - %LV] %TM %MG \n
	* 
	* Exception: %EX \n %ST 
	* 
	* Also time format may be specified in standard java time format in the timeFormat
	* variable The default time format is "dd-MM-yy HH:mm:ss, S"
	*/
	
	public static final String CR = System.getProperty("line.separator");

	private String logPattern;
	private String exceptionPattern;
	private String timeFormat;

	private MessageFormat logMessageFormat;
	private MessageFormat exceptionMessageFormat;
	private DateFormat dateFormat;

	public PatternFormatter()
	{
		LogManager manager = LogManager.getLogManager();
		String cname = getClass().getName();

		timeFormat = manager.getProperty(cname + ".timeFormat");

		if (timeFormat == null)
		{
			timeFormat = "dd-MM-yy HH:mm:ss,S";
		}
		setTimeFormat(timeFormat);

		logPattern = manager.getProperty(cname + ".pattern");
		if (logPattern == null)
		{
			logPattern = "{2} {1}:[{3}][{6}.{7}()] - {4}" + CR;
		}
		setLogPattern(logPattern);

		exceptionPattern = manager.getProperty(cname + ".exceptionPattern");
		if (exceptionPattern == null)
		{
			exceptionPattern = "{2} {1}:[{3}][{6}.{7}()] - {4}" + CR + " [{10}] in {5}: {8} " + CR + "{9}" + CR;
		}
		setExceptionPattern(exceptionPattern);

		logMessageFormat = new MessageFormat(logPattern);
		exceptionMessageFormat = new MessageFormat(exceptionPattern);

		dateFormat = new SimpleDateFormat(timeFormat);
	}

	public void setTimeFormat(String timeFormat)
	{
		this.timeFormat = timeFormat;
		dateFormat = new SimpleDateFormat(timeFormat);
	}

	public void setLogPattern(String logFormat)
	{
		logFormat = logFormat.replace("%LN", "{0}");
		logFormat = logFormat.replace("%LV", "{1}");
		logFormat = logFormat.replace("%TM", "{2}");
		logFormat = logFormat.replace("%TN", "{3}");
		logFormat = logFormat.replace("%MG", "{4}");
		logFormat = logFormat.replace("%SC", "{5}");
		logFormat = logFormat.replace("%CN", "{6}");
		logFormat = logFormat.replace("%SM", "{7}");

		this.logPattern = logFormat;

		logMessageFormat = new MessageFormat(logPattern);
	}

	public void setExceptionPattern(String exceptionFormat)
	{
		exceptionFormat = exceptionFormat.replace("%LN", "{0}");
		exceptionFormat = exceptionFormat.replace("%LV", "{1}");
		exceptionFormat = exceptionFormat.replace("%TM", "{2}");
		exceptionFormat = exceptionFormat.replace("%TN", "{3}");
		exceptionFormat = exceptionFormat.replace("%MG", "{4}");
		exceptionFormat = exceptionFormat.replace("%SC", "{5}");
		exceptionFormat = exceptionFormat.replace("%CN", "{6}");
		exceptionFormat = exceptionFormat.replace("%SM", "{7}");
		exceptionFormat = exceptionFormat.replace("%EX", "{8}");
		exceptionFormat = exceptionFormat.replace("%ST", "{9}");
		exceptionFormat = exceptionFormat.replace("%EN", "{10}");

		this.exceptionPattern = exceptionFormat;

		exceptionMessageFormat = new MessageFormat(logPattern);
	}

	@Override
	public String format(LogRecord record)
	{
		Date time = new Date(record.getMillis());
		String formattedTime = dateFormat.format(time);

		String logMessage = "";

		String sourceClassName = record.getSourceClassName();
		int dotIndex = sourceClassName.lastIndexOf(".");

		if (record.getThrown() == null)
		{
			Object[] log = { record.getLoggerName(), record.getLevel(), formattedTime, Thread.currentThread().getName(), record.getMessage(),
					sourceClassName, dotIndex >=0 ? sourceClassName.substring(dotIndex + 1) : sourceClassName, record.getSourceMethodName() };

			logMessage = logMessageFormat.format(log);
		}
		else
		{

			String stack = getStackAsString(record.getThrown(), "  ");
			
			Object[] log = { record.getLoggerName(), record.getLevel(), formattedTime, Thread.currentThread().getName(), record.getMessage(), 
					sourceClassName, dotIndex >=0 ? sourceClassName.substring(dotIndex + 1) : sourceClassName, record.getSourceMethodName(), record.getThrown().getMessage(), stack,
							record.getThrown().getClass().getName()};

			logMessage = exceptionMessageFormat.format(log);
		}
		return logMessage;
	}

	private String getStackAsString(Throwable t, String indenter)
	{
		indenter = indenter + " ";
		StringBuffer stackBuffer = new StringBuffer();
		
		StackTraceElement[] ste = t.getStackTrace();
		stackBuffer.append(indenter).append(ste[0].toString());
		for (int i = 1; i < ste.length; i++)
		{
			stackBuffer.append(CR).append(indenter).append(ste[i]);
		}

		if (t.getCause() != null)
		{
			stackBuffer.append(CR);
			stackBuffer.append(CR);
			
			stackBuffer.append(indenter).append(" Caused by: [").append(t.getCause().getClass().getName()).append("] ").append(t.getCause().getMessage()).append(CR);
			stackBuffer.append(getStackAsString(t.getCause(), indenter + " "));
			stackBuffer.append(CR);
		}

		return stackBuffer.toString();
	}

	public String getExceptionPattern()
	{
		return exceptionPattern;
	}

	public String getLogPattern()
	{
		return logPattern;
	}

	public String getTimeFormat()
	{
		return timeFormat;
	}

}